package compiler.lexanal;

import java.io.*;

import compiler.report.*;
import compiler.synanal.*;

%%

%class      PascalLex
%public

%line
%column

/* Vzpostavimo zdruzljivost z orodjem Java Cup.
 * To bi lahko naredili tudi z ukazom %cup,
 * a v tem primeru ne bi mogli uporabiti razreda compiler.lexanal.PascalSym
 * namesto razreda java_cup.runtime.Symbol za opis osnovnih simbolov. */
%cupsym     compiler.synanal.PascalTok
%implements java_cup.runtime.Scanner
%function   next_token
%type       PascalSym
%eofval{
	if(count>0){
		Report.warning("["+yylcom+":"+yylcom+"] Odprt komentar!");
	}
    return new PascalSym(PascalTok.EOF);
%eofval}
%eofclose

%{
	private int count=0;
	private int yylcom=0;
	private int yyccom=0;

    private PascalSym sym(int type) {
        return new PascalSym(type, yyline + 1, yycolumn + 1, yytext());
    }
%}

%eof{
%eof}

%state KOMENTAR

%%

<YYINITIAL>{
/* Kljucne besede */

"and"							{ return sym(PascalTok.AND); }
"array"							{ return sym(PascalTok.ARRAY); }
"begin"							{ return sym(PascalTok.BEGIN); }
"const"							{ return sym(PascalTok.CONST); }							
"div"							{ return sym(PascalTok.DIV); }
"do"							{ return sym(PascalTok.DO); }
"else"							{ return sym(PascalTok.ELSE); }
"end"							{ return sym(PascalTok.END); }
"for"							{ return sym(PascalTok.FOR); }
"function"						{ return sym(PascalTok.FUNCTION); }
"if"							{ return sym(PascalTok.IF); }
"nil"							{ return sym(PascalTok.NIL); }
"not"							{ return sym(PascalTok.NOT); }
"of"							{ return sym(PascalTok.OF); }
"or"							{ return sym(PascalTok.OR); }
"procedure"						{ return sym(PascalTok.PROCEDURE); }
"program"						{ return sym(PascalTok.PROGRAM); }
"record"						{ return sym(PascalTok.RECORD); }
"then"							{ return sym(PascalTok.THEN); }
"to"							{ return sym(PascalTok.TO); }
"type"							{ return sym(PascalTok.TYPE); }
"var"							{ return sym(PascalTok.VAR); }
"while"							{ return sym(PascalTok.WHILE); }

/* Imena atomarnih podatkovnih tipov */

"boolean"						{ return sym(PascalTok.BOOL); }
"char"							{ return sym(PascalTok.CHAR); }
"integer"						{ return sym(PascalTok.INT); }

/* Konstante atomarnih podatkovnih tipov: */

"true"|"false"					{ return sym(PascalTok.BOOL_CONST); }
\' [ -&\(-\~] \'|\'\'\'\'		{ return sym(PascalTok.CHAR_CONST); }
[0-9]+							{ return sym(PascalTok.INT_CONST); }

/* Imena programov, konstant, tipov, spremenljivk in podprogramov */

[a-zA-Z_] [a-zA-Z0-9_]*			{ return sym(PascalTok.IDENTIFIER); }

/* Ostali simboli */

":="							{ return sym(PascalTok.ASSIGN); }
":"								{ return sym(PascalTok.COLON); }
","								{ return sym(PascalTok.COMMA); }
"."								{ return sym(PascalTok.DOT); }
".."							{ return sym(PascalTok.DOTS); }
"["								{ return sym(PascalTok.LBRACKET); }
"("								{ return sym(PascalTok.LPARENTHESIS); }
"]"								{ return sym(PascalTok.RBRACKET); }
")"								{ return sym(PascalTok.RPARENTHESIS); }
";"								{ return sym(PascalTok.SEMIC); }
"+"								{ return sym(PascalTok.ADD); }
"="								{ return sym(PascalTok.EQU); }
">="							{ return sym(PascalTok.GEQ); }
">"								{ return sym(PascalTok.GTH); }
"<"								{ return sym(PascalTok.LTH); }
"<="							{ return sym(PascalTok.LEQ); }
"*"								{ return sym(PascalTok.MUL); }
"<>"							{ return sym(PascalTok.NEQ); }
"^"								{ return sym(PascalTok.PTR); }
"-"								{ return sym(PascalTok.SUB); }

/* Komentarji */
"{"								{ count++; yylcom=yyline + 1; yyccom=yycolumn+1; yybegin(KOMENTAR); }

/* Belo besedilo */

[ \r\n\t]+						{ /* ignore */ }

/* Napaka */

.|\n     						{ Report.warning("Neveljaven znak: "+yytext(), yyline + 1, yycolumn + 1); }
}

<KOMENTAR>{
"{"								{ count++;}
"}"								{ count--; if(count==0){yybegin(YYINITIAL);}}
.|\n 							{ /* ignore */ }
}
